home *** CD-ROM | disk | FTP | other *** search
- /*
- * ToDoItem - implementation of ToDoItem, the basic unit of information
- * for the ToDoList program. The method -adjustPriority implements
- * the dynamic priority mechanism.
- *
- * You may freely copy, distribute and reuse the code in this example.
- * This code is provided AS IS without warranty of any kind, expressed
- * or implied, as to its fitness for any particular use.
- *
- * Copyright 1995 Ralph Zazula (rzazula@next.com). All Rights Reserved.
- *
- */
-
- #import "ToDoItem.h"
- #import "RZ.h"
- #import <appkit/appkit.h>
- #import <math.h>
-
- typedef struct _toDoItemFlags {
- #ifdef __BIG_ENDIAN__
- unsigned int type:8;
- unsigned int private:1;
- unsigned int completed:1;
- unsigned int _RESERVED:22;
- #else
- unsigned int _RESERVED:22;
- unsigned int completed:1;
- unsigned int private:1;
- unsigned int type:8;
- #endif
- } toDoItemFlags;
-
- #define _flags ((toDoItemFlags *)_reservedToDoItem1)
-
- @implementation ToDoItem
-
- + initialize
- {
- if([self class] == [ToDoItem class]) {
- [self setVersion:4];
- }
- return self;
- }
-
- - initSubject:(char *)subj startDate:(long)start dueDate:(long)due
- completeDate:(long)completed type:(char)type isPrivate:(BOOL)privateFlag
- isCompleted:(BOOL)completeFlag data:(char *)buf dataLen:(int)len
- {
- if(self = [super init]) {
-
- _flags = (toDoItemFlags *)calloc(1, sizeof(toDoItemFlags));
-
- [self setSubject:subj];
- [self setStartDate:start];
- [self setDueDate:due];
- [self setType:type];
- [self setPrivate:privateFlag];
-
- /* don't want auto-calc of completion so don't use setCompleted: */
- dateCompleted = completed ? completed : 0;
- _flags->completed = completeFlag;
-
- [self setData:buf];
- }
- return self;
- }
-
- - initFromItem:(id <ToDoItems>)anItem
- {
- char *buf;
- int len;
-
- [anItem getData:&buf length:&len];
-
- return [self initSubject:[anItem subject] startDate:[anItem startDate]
- dueDate:[anItem dueDate] completeDate:[anItem dateCompleted]
- type:[anItem type] isPrivate:[anItem isPrivate]
- isCompleted:[anItem isCompleted] data:buf dataLen:len];
- }
-
- - init
- {
- return [self initSubject:NULL startDate:time(NULL) dueDate:(time(NULL)+60)
- completeDate:0 type:TODO_TYPE_NORMAL isPrivate:NO isCompleted:NO
- data:NULL dataLen:0];
- }
-
- - free
- {
- if(subject) {
- NX_FREE(subject);
- subject = NULL;
- }
- if(data) {
- NX_FREE(data);
- data = NULL;
- dataLen = 0;
- }
-
- free(_flags);
- return [super free];
- }
-
- - (char *)subject { return subject; }
- - (long)priority { return priority; }
- - (long)startDate { return startDate; }
- - (long)dueDate { return dueDate; }
- - (long)dateCompleted { return dateCompleted; }
- - (char)type { return _flags->type; }
- - (BOOL)isPrivate { return _flags->private; }
- - (BOOL)isCompleted { return _flags->completed; }
-
- - (const char *)asciiStartDate
- {
- static char buf[40];
-
- if(!startDate) {
- return NULL;
- }
-
- strftime(buf, 40, "%m/%d/%y", localtime(&startDate));
-
- return buf;
- }
-
- - (const char *)asciiCompletedDate
- {
- static char buf[40];
-
- if(!dateCompleted) {
- return NULL;
- }
-
- strftime(buf, 40, "%m/%d/%y", localtime(&dateCompleted));
-
- return buf;
- }
-
- - (const char *)asciiDueDate
- {
- static char buf[40];
-
- switch(_flags->type) {
- case TODO_TYPE_NORMAL :
- case TODO_TYPE_APPOINTMENT :
- strftime(buf, 40, "%m/%d/%y", localtime(&dueDate));
- break;
- case TODO_TYPE_HIGHPRIORITY :
- sprintf(buf, "ASAP!");
- break;
- case TODO_TYPE_LOWPRIORITY :
- sprintf(buf, "LATER");
- break;
- }
-
- return buf;
- }
-
- - getData:(char **)d length:(int *)len
- {
- *d = data;
- *len = dataLen;
- return self;
- }
-
- - setSubject:(const char *)s
- {
- subject = RZReplaceStringBuffer(&subject, s);
- return self;
- }
-
- - setPriority:(long)p
- {
- priority = p;
- return self;
- }
-
- - setStartDate:(long)newDate
- {
- startDate = newDate;
- return self;
- }
-
- - setDueDate:(long)newDate
- {
- dueDate = newDate;
- [self adjustPriority];
- return self;
- }
-
- - setType:(char)newType
- {
- _flags->type = newType;
- priority = 0;
-
- return self;
- }
-
- - setPrivate:(BOOL)flag
- {
- _flags->private = flag;
- return self;
- }
-
- - setCompleted:(BOOL)flag
- {
- _flags->completed = flag;
- dateCompleted = flag ? time(NULL) : 0;
- return self;
- }
-
- - setData:(const char *)d
- {
- RZReplaceStringBuffer(&data, d);
- dataLen = data ? strlen(data) + 1 : 0;
- return self;
- }
-
- - setDataFromText:aText
- {
- NXStream *stream;
- BOOL failed = NO;
-
- stream = NXOpenMemory(NULL, 0, NX_READWRITE);
- NX_DURING
- [aText writeRichText:stream];
- NX_HANDLER
- failed = YES;
- NX_ENDHANDLER
- if(!failed) {
- [self setDataFromStream:stream];
- NXCloseMemory(stream, NX_FREEBUFFER);
- }
-
- return self;
- }
-
- - setDataFromStream:(NXStream *)stream
- {
- char *_data;
- int _dataLen, _maxLen;
-
- NXGetMemoryBuffer(stream, &_data, &_dataLen, &_maxLen);
- [self setData:_data];
-
- return self;
- }
-
- - writeToStream:(NXStream *)stream
- {
- static id dummyText = nil;
-
- NXPrintf(stream, "Subject: %s\n",[self subject]);
- switch(_flags->type) {
- case TODO_TYPE_NORMAL :
- NXPrintf(stream, "Type: Normal\n");
- break;
-
- case TODO_TYPE_APPOINTMENT :
- NXPrintf(stream, "Type: Appointment\n");
- break;
-
- case TODO_TYPE_LOWPRIORITY :
- NXPrintf(stream, "Type: Low Priority\n");
- break;
-
- case TODO_TYPE_HIGHPRIORITY :
- NXPrintf(stream, "Type: High Priority\n");
- break;
- }
- NXPrintf(stream, "Created: %s\n",[self asciiStartDate]);
- NXPrintf(stream, "Due on: %s\n",[self asciiDueDate]);
- if(_flags->completed) {
- NXPrintf(stream, "Completed: %s\n",[self asciiCompletedDate]);
- }
- NXPrintf(stream, "\n");
- if(dataLen) {
- NXStream *_stream;
- if(!dummyText) {
- dummyText = [[Text alloc] init];
- }
- _stream = NXOpenMemory(NULL, 0, NX_READWRITE);
- NXWrite(_stream, data, dataLen);
- NXSeek(_stream, 0, NX_FROMSTART);
- [dummyText readRichText:_stream];
- NXCloseMemory(_stream, NX_FREEBUFFER);
- [dummyText writeText:stream];
- }
- return self;
- }
-
- #define LOW_PRIORITY_BASE 0
- #define LOW_PRIORITY_SIZE 256
- #define LOW_PRIORITY_MAX (LOW_PRIORITY_BASE + LOW_PRIORITY_SIZE)
- #define NORMAL_PRIORITY_BASE (LOW_PRIORITY_MAX + 1)
- #define NORMAL_PRIORITY_SIZE 512
- #define NORMAL_PRIORITY_MAX (NORMAL_PRIORITY_BASE + NORMAL_PRIORITY_SIZE)
- #define HIGH_PRIORITY_BASE (NORMAL_PRIORITY_MAX + 1)
- #define HIGH_PRIORITY_SIZE 256
- #define HIGH_PRIORITY_MAX (HIGH_PRIORITY_BASE + HIGH_PRIORITY_SIZE)
-
- #define ONE_DAY (60*60*24)
- #define ONE_YEAR (60*60*24*365)
- #define OLDEST_ITEM ONE_YEAR
-
- - adjustPriority
- /*
- * priority quantizer - I've decided to quantize priorities in the
- * range 0 - 1023 (if you have more than 1K of stuff to do, you're
- * in trouble :-) The priority space is divided into three regions:
- * 0 - 255 LOW PRIORITY ITEMS
- * 256 - 767 NORMAL PRIORITY ITEMS
- * 768 - 1023 HIGH PRIORITY ITEMS
- */
- {
- long age = time(NULL) - startDate;
- long deadline = dueDate - time(NULL);
-
- if(_flags->completed) {
- priority = -dateCompleted;
- return self;
- }
-
- switch(_flags->type) {
- case TODO_TYPE_LOWPRIORITY :
- /* accrue priority over time but never get above LOW_PRIORITY_MAX */
- priority = LOW_PRIORITY_BASE +
- LOW_PRIORITY_SIZE*((float)age/(float)OLDEST_ITEM);
- priority = MIN(priority, LOW_PRIORITY_MAX);
- break;
-
- case TODO_TYPE_NORMAL :
- /* increase priority as we get nearer the deadline */
- if(deadline > 0) {
- /* quantize the time until the deadline */
- priority = NORMAL_PRIORITY_MAX -
- NORMAL_PRIORITY_SIZE*((float)deadline/(float)OLDEST_ITEM);
- } else {
- /* past the due date, make max priority */
- priority = NORMAL_PRIORITY_MAX;
- }
- priority = MIN(priority, NORMAL_PRIORITY_MAX);
- break;
-
- case TODO_TYPE_HIGHPRIORITY :
- /* accrue priority over time but never get above HIGH_PRIORITY_MAX */
- priority = HIGH_PRIORITY_BASE +
- HIGH_PRIORITY_SIZE*((float)age/(float)OLDEST_ITEM);
- priority = MIN(priority, HIGH_PRIORITY_MAX);
- break;
-
- case TODO_TYPE_APPOINTMENT :
- /* drop into an appropriate slot based on the appointment date */
- if(deadline > 10*ONE_DAY) {
- priority = LOW_PRIORITY_MAX;
- } else if(deadline < 2*ONE_DAY) {
- priority = HIGH_PRIORITY_MAX;
- } else {
- priority = NORMAL_PRIORITY_MAX;
- }
- break;
-
- }
-
- return self;
- }
-
- - awake
- {
- [self adjustPriority];
- return self;
- }
-
- - read:(NXTypedStream *)ts
- {
- [super read:ts];
- _flags = (toDoItemFlags *)calloc(1,sizeof(toDoItemFlags));
-
- switch(NXTypedStreamClassVersion(ts, [[self class] name])) {
- case 4 :
- NXReadTypes(ts, "*llll*iI",
- &subject, &priority, &startDate, &dueDate, &dateCompleted,
- &data, &dataLen, _flags);
- break;
-
- case 3 :
- NXReadTypes(ts, "*llll*ii",
- &subject, &priority, &startDate, &dueDate, &dateCompleted,
- &data, &dataLen, _flags);
- break;
-
- case 2 :
- NXReadTypes(ts, "*lll*ii",
- &subject, &priority, &startDate, &dueDate, &data, &dataLen, _flags);
- break;
-
- case 1 :
- NXReadTypes(ts, "*lll*ic",
- &subject, &priority, &startDate, &dueDate, &data, &dataLen, &_flags->type);
- break;
-
- case 0 :
- NXReadTypes(ts, "*lll*i",
- &subject, &priority, &startDate, &dueDate, &data, &dataLen);
- break;
- }
-
- return self;
- }
-
- - write:(NXTypedStream *)ts
- {
- [super write:ts];
- NXWriteTypes(ts, "*llll*iI",
- &subject, &priority, &startDate, &dueDate, &dateCompleted,
- &data, &dataLen, _flags);
- return self;
- }
-
- @end
-